package com.song.server;

import com.song.NacosServiceRegistry.NacosServiceRegistry;
import com.song.Utils.ReflectUtil;
import com.song.autoscanner.Service;
import com.song.autoscanner.ServiceScan;
import com.song.enumeration.RpcError;
import com.song.exception.RpcException;
import com.song.registry.ServiceRegistry;
import com.song.serprovider.ServiceProvider;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.util.Set;

/**
 * 抽象类实现RpcServer接口， 抽象类不能实例化对象，所以抽象类必须被继承，才能被使用
 * 由NettyServer继承
 */
@Slf4j(topic = "c.AbstractRpcServer")
public abstract class AbstractRpcServer implements RpcServer{
    protected String host;
    protected int port;

    protected ServiceProvider serviceProvider;//向本地注册服务
    protected NacosServiceRegistry serviceRegistry;//向Nacos注册服务

    public void scanServices() throws Exception {
        log.info("自动寻找服务。。。");

        String mainClassName = ReflectUtil.getStackTrace();//com.song.NettyTest.NettyTestServer
        Class<?> startClass;

        try {
            startClass = Class.forName(mainClassName);//com.song.NettyTest.NettyTestServer

            if(!startClass.isAnnotationPresent(ServiceScan.class)) {////@interface ServiceScan
                log.error("启动类缺少 @ServiceScan 注解");
                throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_NOT_FOUND);
            }
        } catch (ClassNotFoundException e) {
            log.error("出现未知错误");
            throw new RpcException(RpcError.UNKNOWN_ERROR);
//            e.printStackTrace();
        }

        String basePackage = startClass.getAnnotation(ServiceScan.class).value();
        if("".equals(basePackage)) {
            basePackage = mainClassName.substring(0, mainClassName.lastIndexOf("."));//NettyTest
        }

        //在NettyTest 包下面寻找所有的类
        //主要就是 getClasses 方法，传入一个包名，用于扫描该包及其子包下所有的类，并将其 Class 对象放入一个 Set 中返回
        Set<Class<?>> classSet = ReflectUtil.getClasses(basePackage);
        for(Class<?> clazz : classSet) {
            if(clazz.isAnnotationPresent(Service.class)) {
                String serviceName = clazz.getAnnotation(Service.class).name();
                Object obj;

                try {
                    obj = clazz.newInstance();
                } catch (InstantiationException | IllegalAccessException e) {
//                    e.printStackTrace();
                    log.error("创建" + clazz + "时有错误发生");
                    continue;
                }

                if("".equals(serviceName)) {
                    Class<?>[] interfaces = clazz.getInterfaces();

                    for(Class<?> oneinterface : interfaces) {
                        publishService(obj, oneinterface.getCanonicalName());
                    }
                } else {
                    publishService(obj, serviceName);
                }
            }
        }
    }

    @Override
    public <T> void publishService(T service, String serviceName) throws Exception {
        serviceProvider.addServiceProvider(service, serviceName);
        log.info("注册了服务" + serviceName);
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }

}
